﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GameLib.Gameplay;

namespace GameLib.Serialization
{
	public abstract class DataHandler
	{
		public virtual void Read(object obj, string dataPath)
		{
			DataType dataType = ExtractDataType(ref dataPath);
			Serializer serializer = GetSerializer(obj.GetType(), dataType);

			if (serializer == null || !serializer.Deserialize(obj, dataPath))
				throw new Exception(string.Format("Object {0} (type:{1}) from path {2} is not readable!", obj, obj.GetType(), dataPath));
		}

		public virtual void Write(object obj, string dataPath)
		{
			DataType dataType = ExtractDataType(ref dataPath);
			Serializer serializer = GetSerializer(obj.GetType(), dataType);

			if (serializer == null || !serializer.Serialize(obj, dataPath))
				throw new Exception(string.Format("Object {0} (type:{1}) to path {2} is not writable!", obj, obj.GetType(), dataPath));
		}

		public Serializer GetSerializer(Type objType, DataType dataType)
		{
			SerializerCollection serializerCollection;

			if (!Serializers.TryGetValue(dataType, out serializerCollection))
				return null;

			return serializerCollection.FindSerializerFor(objType);
		}

		protected void RegisterSerializer(Serializer serializer)
		{
			serializer.DataHandler = this;

			SerializerCollection serializerCollection;

			if (!Serializers.TryGetValue(serializer.DataType, out serializerCollection))
			{
				serializerCollection = new SerializerCollection();
				Serializers[serializer.DataType] = serializerCollection;
			}

			serializerCollection.Add(serializer);
		}

		protected virtual DataType ExtractDataType(ref string dataPath)
		{
			string[] pathAndDataType = dataPath.Split(";".ToCharArray());

			if (pathAndDataType.Length >= 2)
			{
				if (pathAndDataType.Length > 2)
					throw new Exception(string.Format("Invalid data path (more than two ';') : {0}", dataPath));

				dataPath = pathAndDataType[0];
				return DataType.FindDataType(pathAndDataType[1]);
			}
			else
			{
				// check extension
				int extStart = dataPath.LastIndexOf('.') + 1;

				if (extStart > 0 && extStart < dataPath.Length)
				{
					return DataType.FindDataTypeByExt(dataPath.Substring(extStart));
				}
			}

			return null;
		}

		private Dictionary<DataType, SerializerCollection> Serializers = new Dictionary<DataType, SerializerCollection>();
	}
}
